package com.springboot.core.vaildate;

import com.alibaba.fastjson.JSON;
import com.springboot.core.exception.BizException;
import com.springboot.core.exception.ErrorBuilder;
import com.springboot.core.log.BaseLogger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validator;
import java.lang.annotation.Annotation;
import java.util.*;

/**
 * On 2017/3/6 0006.
 */
@Component
@Aspect
public class ParamterValidateAop extends BaseLogger {
    private final Validator validator;
    private final VaildationProperties properties;

    @Autowired
    public ParamterValidateAop(Validator validator, VaildationProperties properties) {
        this.validator = validator;
        this.properties = properties;
    }



    @Pointcut("execution(* com.springboot..service.impl.*.*(..))")
    public void aspect(){
        System.out.println("vaild pointcut");
    }

    /**
     * 查找Valid 注解符号
     * @param joinPoint     编入的对象
     * @return  找到返回True 否则返回false
     */
    private Boolean findValidAnnotation(JoinPoint joinPoint){
        Annotation[][] annotations = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterAnnotations();
        if(annotations.length > 0){
            Annotation[] pAnnotations = annotations[0];
            long count = Arrays.stream(pAnnotations).filter(e ->
                    e.annotationType().getName().equals(Valid.class.getName())
            ).count();
            return count > 0 ? Boolean.TRUE : Boolean.FALSE;
        }
        return Boolean.FALSE;
    }

    /**
     * aop前置方法,进行接口参数验证
     * @param jp    编入对象
     */
    @Before("aspect()")
    public void validate(JoinPoint jp){
        //首先判断是否开启服务层验证,再判断是否存在Valid注解
        if(properties.getOpenServiceValidation() && findValidAnnotation(jp)){
            Object parameter = jp.getArgs()[0];
            Set<ConstraintViolation<Object>> error = validator.validate(parameter);
            if(null !=  error && !error.isEmpty()){
                List<Map<String,String>> list = new ArrayList<>();
                error.stream().forEach(e->{
                    Map<String,String> field = new HashMap<>();
                    field.put("field",e.getPropertyPath().toString());
                    field.put("message",e.getMessage());
                    list.add(field);
                });
                throw  new BizException().setError(ErrorBuilder.buildBindError(JSON.toJSONString(list)));
            }
        }
    }
}
